package balgo.ga;

import java.util.ArrayList;
import java.util.List;

/**
 * AdorynZhao in Toutiao-UESTC.
 * Source Code Created on 2017/12/28.
 */
public class TChromosome {
    private boolean[] gene = null;
    private double score = 0;

    public double getScore() {
        return this.score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    private void initGeneSize(int size) {
        if (size <= 0)
            return;

        gene = new boolean[size];
    }

    // 生成一个新基因
    public TChromosome() { }

    // 随机生成基因序列
    public TChromosome(int size) {
        if (size <= 0) {
            return;
        }
        this.initGeneSize(size);
        for (int i = 0; i < size; i++) {
            this.gene[i] = Math.random() >= 0.5;
        }
    }

    // 基因num个位子发生变异
    public void mutation(int num) {
        int size = this.gene.length;
        for (int i = 0; i < num; i++) {
            int at = ((int)(Math.random() * size)) % size;
            this.gene[at] = !this.gene[at];
        }
    }

    // 将基因转化为对应的数字
    public int getNum() {
        if (this.gene == null)
            return 0;

        int num = 0;
        for (boolean b : gene) {
            num <<= 1;
            if (b)
                num += 1;
        }

        return num;
    }

    // 基因克隆
    public static TChromosome clone(final TChromosome c) {
        if (c == null || c.gene == null)
            return null;

        TChromosome copy = new TChromosome();
        copy.initGeneSize(c.gene.length);
        for (int i = 0; i < c.gene.length; i++) {
            copy.gene[i] = c.gene[i];
        }

        return copy;
    }

    // 遗传产生下一代
    public static List<TChromosome> genetic(TChromosome p1, TChromosome p2) {
        if (p1 == null || p2 == null)
            return null;

        if (p1.gene == null || p2.gene == null)
            return null;

        if (p1.gene.length != p2.gene.length)
            return null;

        TChromosome c1 = clone(p1);
        TChromosome c2 = clone(p2);

        // 随机产生交叉互换位置
        int size = c1.gene.length;
        int a = ((int)(Math.random() * size)) % size;
        int b = ((int)(Math.random() * size)) % size;
        int min = a > b ? b : a;
        int max = a > b ? a : b;

        // 对位置上的基因进行交叉互换
        for (int i = min; i <= max; i++) {
            boolean t = c1.gene[i];
            c1.gene[i] = c2.gene[i];
            c2.gene[i] = t;
        }

        List<TChromosome> list = new ArrayList<>();
        list.add(c1);
        list.add(c2);

        return list;
    }
}
